package cn.org.xuanguang.kepler.hormos.rdb.jpa.mapper;


import cn.org.xuanguang.kepler.hormos.rdb.dml.warrper.ColumnWrapperContext;
import cn.org.xuanguang.kepler.hormos.rdb.jpa.*;
import cn.org.xuanguang.kepler.hormos.rdb.jpa.generation.GenerationValues;
import cn.org.xuanguang.kepler.hormos.rdb.jpa.generation.JPAProvider;
import cn.org.xuanguang.kepler.hormos.rdb.util.EnumUtils;
import cn.org.xuanguang.kepler.hormos.rdb.util.StyleUtil;
import cn.org.xuanguang.kepler.metadata.relational.KeplerMetaTable;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.List;

/**
 * 元数据到dsl的转换工具类
 *  <p>
 *   sql操作
 *        1、update，insert，列信息，值信息
 *        2、select，查询条件，列信息，值信息
 *        3、delete，删除条件，列信息，值信息
 *  *  3、
 *  </p>
 * @author xuanguang
 * @since 2.0
 */
public class MetaTableToDslUtils {
    // 日志
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
//    sql操作
// *   sql操作
// *        1、update，insert，列信息，值信息
// *        2、select，查询条件，列信息，值信息
// *        3、delete，删除条件，列信息，值信息
    /**
     * 通过DSL语法在指定的KeplerMetaTable上操作实体。
     *
     * @param metaTable KeplerMetaTable对象，代表要操作的数据表元信息。
     * @param entity    实体对象，泛型T继承自IEntity，代表要进行操作的具体实体。
     * @param <T>       泛型参数，限定为IEntity的子类型，用于指定实体的类型。
     * @return
     */
    @SneakyThrows
    public static <T> void dsl(KeplerMetaTable metaTable, T entity, List<JpaColumnMapper> jpaColumnMappers) {
        Class<?> clazz =  entity.getClass();
        while (clazz != null) {
            // 当前类
            addJpaColumnMapper(clazz.getDeclaredFields(), entity, jpaColumnMappers);
            clazz = clazz.getSuperclass(); // 获取超类，继续遍历
        }
    }

    /**
     * 加载列信息，值信息
     * @param fields
     * @param entity
     * @param jpaColumnMappers
     * @param <T>
     */
    @SneakyThrows
    private static <T> void addJpaColumnMapper(Field[] fields, T entity, List<JpaColumnMapper> jpaColumnMappers) {
        for (Field field : fields) {
            field.setAccessible(true);
            // 获取字段的名称
            String fieldName = field.getName();
            Object value = field.get(entity);
            JpaColumnMapper context = new JpaColumnMapper();
            context.setFiled(fieldName);
            // 字段类型
            context.setType(field.getType().getName());
            //注解处理,只有标记了Column的才处理
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                if ("".equals(column.columnName())) {
                    // 如果没配置，则默认为字段名，默认为驼峰命名
                    fieldName = StyleUtil.camelhumpToUnderline(fieldName);
                } else {
                    fieldName = column.columnName();
                }
            }
            context.setColumn(fieldName);
            // 处理id
            if (field.isAnnotationPresent(Id.class) && field.isAnnotationPresent(GeneratedValue.class) && value == null) {
                // 自动生成id
                value = GenerationValues.of(field.getAnnotation(GeneratedValue.class).generator()).getValue(context.getType());
            }
            // 处理 Creator和Updator
            if (field.isAnnotationPresent(Creator.class)) {
                // 实例化注解提供器
                Class<?> creatorClass = field.getAnnotation(Creator.class).provider();
                // 实例化creatorClass
                JPAProvider<?> jpaProvider = (JPAProvider<?>) creatorClass.getDeclaredConstructor(Class.class).newInstance(field.getType());
                value = jpaProvider.getValue();
            }
            if (field.isAnnotationPresent(Updator.class)) {
                // 实例化注解提供器
                Class<?> updatorClass = field.getAnnotation(Updator.class).provider();
                // 实例化creatorClass
                JPAProvider<?> jpaProvider = (JPAProvider<?>) updatorClass.getDeclaredConstructor(Class.class).newInstance(field.getType());
                value = jpaProvider.getValue();
            }
            //处理枚举值
            if (field.getType().isEnum()) {
                if (value != null) {
                    Enumerated enumerated = field.getAnnotation(Enumerated.class);
                    //获取映射的属性

                    if (enumerated != null && enumerated.value() == EnumType.STRING) {
                        String mappingFiled = enumerated.mapping();
                        if (!"".equals(mappingFiled)) {
//                           获取枚举的所有枚举常量
                            Enum[] enumConstants = (Enum[]) field.getType().getEnumConstants();
                            for (Enum enumConstant : enumConstants) {
                                if (enumConstant.name().equals(value.toString())) {
                                    if (enumConstant.getClass().getDeclaredField(mappingFiled).getType().isEnum()) {
                                        // 枚举嵌套枚举
                                        value = EnumUtils.getEnumValue(enumConstant.getClass().getDeclaredField(mappingFiled).getType(), value.toString());
                                    }
                                    Field enmuField = enumConstant.getClass().getDeclaredField(mappingFiled);
                                    enmuField.setAccessible(true);
                                    value = enmuField.get(enumConstant);
                                    break;
                                }
                            }
                        } else {
                            value = EnumUtils.getEnumValue(field.getType(), value.toString());
                        }
                    }
                }
            }
            context.setValue(value);

            // null值 不存
            if (value == null) {
                continue;
            }
            jpaColumnMappers.add(context);
        }
    }

    /**
     * sql-转jpa的javabean的包装
     *
     * @param result  实例
     * @param entity  jpa类
     * @param context sql结果行bean
     * @param <T>
     */
    public static <T> void columnWrapper(T result, Class<T> entity, ColumnWrapperContext<T> context) {
        //优化，需要把所有的字段都处理一遍，包括所有的超类
        while (entity != null) {
            // 当前类
            Field[] fields = entity.getDeclaredFields();
            addEntityColumnWrapper(fields, result, context);

            entity = (Class<T>) entity.getSuperclass(); // 获取超类，继续遍历
        }

    }

    private static <T> void addEntityColumnWrapper(Field[] fields, T result, ColumnWrapperContext<T> context) {
        for (Field field : fields) {
            String fieldName = field.getName();
            Object value = context.getResult();
            field.setAccessible(true);
            //注解处理
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                if ("".equals(column.columnName())) {
                    // 如果没配置，则默认为字段名，默认为驼峰命名
                    fieldName = StyleUtil.camelhumpToUnderline(fieldName);
                } else {
                    fieldName = column.columnName();
                }
            }
            // todo 理论上，此处应该校验，sql类型和jpa的类型是否一致，我偷懒，没写，嘿嘿
            // 全部处理成小写，方便对比
            if (fieldName.equalsIgnoreCase(context.getColumnLabel())) {
                try {
                    //处理枚举值
                    if (field.getType().isEnum()) {
                        if (value != null) {
                            value = EnumUtils.getEnumValue(field.getType(), value.toString());
                        }
                    }
                    field.set(result, value);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

}
